package validator

import (
	"math"
	"reflect"
	"strconv"

	"github.com/dlclark/regexp2"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
	"xincan.com.cn/tarot-go/internal/components/logging"
)

const (
	ValidNumLen   = "v-num-len"
	ValidPassword = "v-password"
)

// ValidRuleInfo 包含验证规则的完整信息
type ValidRuleInfo struct {

	// Tag 标签
	Tag string

	// Message 提示信息
	Message string

	// TranslateFunc 翻译函数
	TranslateFunc func() error

	// RuleFunc 验证规则函数
	RuleFunc func(fl validator.FieldLevel) bool
}

// ruleValidator
// Title    			ruleValidator
// Description   		自定义验证器规则结构体
// Author      			alittlexincan@163.com         	2024/07/22 11:36
// Update    			alittlexincan@163.com         	2024/07/22 11:36
type ruleValidator struct {

	// logger 日志
	logger *logging.TraceLogger

	// validate 验证器
	Validate *validator.Validate

	// trans 翻译器
	Trans ut.Translator

	// rules 验证规则
	rules map[string]*ValidRuleInfo
}

// RuleValidatorBuilder
// Title 			RuleValidatorBuilder
// Description 		自定义验证器规则构造器结构体
// Author      		alittlexincan@163.com         						2024/07/22 11:36
// Update  			alittlexincan@163.com         						2024/07/22 11:36
type RuleValidatorBuilder struct {
	*ruleValidator
}

// NewRuleValidatorBuilder
// Title NewRuleValidatorBuilder
// Description 		创建自定义验证器规则构造器实例
// Author      		alittlexincan@163.com         						2024/07/22 11:36
// Update  			alittlexincan@163.com         						2024/07/22 11:36
// Return    		*RuleValidatorBuilder    							返回自定义验证器规则构造器实例
func NewRuleValidatorBuilder() *RuleValidatorBuilder {
	return &RuleValidatorBuilder{
		&ruleValidator{
			rules: make(map[string]*ValidRuleInfo),
		},
	}
}

// WithLogger
// Title 			WithLogger
// Description 		设置验证器: 日志组件
// Author      		alittlexincan@163.com       							2024/07/22 11:36
// Update  			alittlexincan@163.com       							2024/07/22 11:36
// Param    		logger 				*logging.TraceLogger 				传入日志组件
// Return    		*RuleValidatorBuilder										返回验证器实例
func (builder *RuleValidatorBuilder) WithLogger(logger *logging.TraceLogger) *RuleValidatorBuilder {
	builder.logger = logger
	return builder
}

// WithValidator
// Title 			WithValidator
// Description 		设置验证器: 验证器
// Author      		alittlexincan@163.com       							2024/07/22 11:36
// Update  			alittlexincan@163.com       							2024/07/22 11:36
// Param    		validator 				*validator.Validate				验证器
// Return    		*RuleValidatorBuilder										返回验证器实例
func (builder *RuleValidatorBuilder) WithValidator(validator *validator.Validate) *RuleValidatorBuilder {
	builder.Validate = validator
	return builder
}

// WithTrans
// Title 			WithTrans
// Description 		设置验证器: 翻译器
// Author      		alittlexincan@163.com       							2024/07/22 11:36
// Update  			alittlexincan@163.com       							2024/07/22 11:36
// Param    		trans 				*ut.Translator						翻译器
// Return    		*RuleValidatorBuilder										返回验证器实例
func (builder *RuleValidatorBuilder) WithTrans(trans ut.Translator) *RuleValidatorBuilder {
	builder.Trans = trans
	return builder
}

// Build
// Title Build
// Description 		创建自定义验证器规则实例
// Author      		alittlexincan@163.com         						2024/07/22 11:36
// Update  			alittlexincan@163.com         						2024/07/22 11:36
// Return    		map[string]*ValidRuleInfo    						返回自定义验证器规则实例
func (builder *RuleValidatorBuilder) Build() map[string]*ValidRuleInfo {
	return builder.GetRules()
}

// GetRules
// Title    		GetRules
// Description   	获取所有规则
// Author      		alittlexincan@163.com         						2024/07/22 11:36
// Update    		alittlexincan@163.com         						2024/07/22 11:36
// Return    		map[string]*ValidRuleInfo    						返回所有规则
func (rule *ruleValidator) GetRules() map[string]*ValidRuleInfo {
	// 注册所有规则
	rule.RegisterRule(ValidNumLen, "{0}格式不正确, 长度为{1}位数字", rule.CheckIdLengthValidator)
	rule.RegisterRule(ValidPassword, "{0}格式不正确, 必须同时包含至少大写字母小写字母和数字各一个", rule.PasswordValidator)
	return rule.rules
}

// RegisterRule
// Title    		RegisterRule
// Description   	注册自定义验证器规则
// Author      		alittlexincan@163.com         									2024/07/22 11:36
// Update  			alittlexincan@163.com         									2024/07/22 11:36
// Param    		tag 						string								验证标签
// Param    		message 					string								验证失败提示信息
// Param    		ruleFunc 					func(fl validator.FieldLevel) bool	验证函数
func (rule *ruleValidator) RegisterRule(tag string, message string, ruleFunc func(fl validator.FieldLevel) bool) {
	rule.rules[tag] = &ValidRuleInfo{
		Tag:     tag,
		Message: message,
		TranslateFunc: func() error {
			// 注册翻译，并提供自定义格式化函数
			return rule.Validate.RegisterTranslation(tag, rule.Trans,
				func(ut ut.Translator) error {
					return ut.Add(tag, message, true)
				},
				func(ut ut.Translator, fe validator.FieldError) string {
					// // 自动处理 {0} 和 {1} 的替换, {0} 会被替换为字段名（通过label标签获取）, {1} 会被替换为验证规则的参数（如v-num-len=15中的15）
					t, err := ut.T(tag, fe.Field(), fe.Param())
					if err != nil {
						return fe.(error).Error()
					}
					return t
				},
			)
		},
		RuleFunc: ruleFunc,
	}
}

// CheckIdLengthValidator
// Title    		CheckIdLengthValidator
// Description   	ID长度验证器: 验证ID长度是否为Int64类型的19位
//   - 当前字段如果不是int64类型，则跳过验证
//   - 检查是否大于 math.MaxInt64, 如果是，返回 false
//   - 返回 true 表示验证通过
//
// Author      		alittlexincan@163.com         					2024/07/22 11:36
// Update    		alittlexincan@163.com         					2024/07/22 11:36
// Param			fl 						validator.FieldLevel	传入验证字段
// Return    		bool											返回验证结果
func (rule *ruleValidator) CheckIdLengthValidator(fl validator.FieldLevel) bool {
	field := fl.Field()
	attrValue := field.Int() // 获取属性值
	attrType := field.Kind() // 获取属性类型
	_ = fl.GetTag()          // 自定义标签名称
	tagValue := fl.Param()   // 自定义标签值
	if attrType != reflect.Int64 {
		return true // 如果不是 int64 类型，跳过验证（可以根据需要调整）
	}
	// 检查是否大于 math.MaxInt64
	if attrValue >= math.MaxInt64 {
		return false
	}
	attrValueLen := len(strconv.FormatInt(attrValue, 10))
	// 将字attrType符串转为 int64
	tagLen, _ := strconv.Atoi(tagValue)
	return attrValueLen == tagLen
}

// PasswordValidator
// Title    		PasswordValidator
// Description   	密码验证器: 验证密码是否符合要求
//   - 密码长度为8到20个字符
//   - 包含数字、小写字母、大写字母
//
// Author      		alittlexincan@163.com         					2024/07/22 11:36
// Update    		alittlexincan@163.com         					2024/07/22 11:36
// Param			field 					validator.FieldLevel	传入验证字段
// Return    		bool											返回验证结果
func (rule *ruleValidator) PasswordValidator(field validator.FieldLevel) bool {
	// 正则表达式解释：
	// ^(?=.*[0-9]) 前瞻断言，确保至少有一个数字
	// (?=.*[a-z]) 前瞻断言，确保至少有一个小写字母
	// (?=.*[A-Z]) 前瞻断言，确保至少有一个大写字母
	// .{8,20}$ 确保长度为8到20个任意字符
	passwordRegex := "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,20}$"
	reg, _ := regexp2.Compile(passwordRegex, 0)
	matched, err := reg.FindStringMatch(field.Field().String())
	if err != nil {
		rule.logger.Error("PasswordValidator", zap.Any("err", err))
		return false
	}
	return matched != nil
}
